/******************************************************************************
MSP430g2553 Generic I2C slave PWM peripheral

This code does two things:
1)	Blinks an LED on P1.0 on and off with a period of 1 second

2)	Reads a joystick on two of the ADC inputs, and drives the PWM based on the
	joystick value

*******************************************************************************/

#include "msp430g2553.h"
#include "util.h"

#define	I2C_OWN_ADDR	0x20		// address 0x40 -> we receive from master, 0x41 -> we write byte to I2C bus

unsigned char	i2cdata = 0x00;	// scratch pad for playing with i2c info

#define	NUM_REG	3
unsigned char registers[NUM_REG];

unsigned int timecnt = 0;

#define NUM_SAMPLES 6
unsigned int data[NUM_SAMPLES];	// data buffer for ADC DTC

#define PWM_INITIAL 0x7f		// half range

void setup_ADC() {
	// ADC10 setup - we care only about A4 and A5, but we will use the DTC to get A5-A0
	// all at once and only use the top two values

	ADC10CTL0 = SREF_0 + 		// Vcc and GND as references
//				ADC10SHT_1 +	// 8 x ADC10CLKs
				ADC10SHT_3 +	// 64 x ADC10CLKs = 12.8uS
				MSC +			// we want to convert until done with sequence
				ADC10ON +		// turn unit on...
				ADC10IE;		// enable interrupt
	

	ADC10CTL1 = INCH_5 +		// A5 start (will use DTC)
				SHS_0 +			// use ADC10SC as sample start trigger
				ADC10DF * 0 +	// ADC10DF set to 0 - not 2s complement
				ADC10DIV_0 + 	// use /1 divider on clock, each 200ns
				ADC10SSEL_0 + 	// ADC10OSC as input clock		
				CONSEQ_1; 		// sequence of channels
				
	ADC10DTC0 = 0;				// all defaults - one block xfer, stop after 1 block 
	ADC10DTC1 = NUM_SAMPLES;	// going to get A5 through A0 - 6 samples
	
	// will not actually sample A3-A0, since the pin is not set to connect to ADC
	SET_BIT8(ADC10AE0, 4);		// configure to use A4 
	SET_BIT8(ADC10AE0, 5);		// configure to use A5 
	
	SET_BIT8(P1SEL, 4);			// use as analog I/O
	SET_BIT8(P1SEL, 5);			// use as analog I/O
	
	ADC10CTL0 |= ENC;			// enable the ADC after setting configuration (bit 1)
}

void main(void) {
	
	// stop the watchdog timer
	WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
	
	// set up internal clocking
	if (CALBC1_16MHZ ==0xFF || CALDCO_16MHZ == 0xFF) while(1);	// set up to use internal oscillator                                             
	DCOCTL = CALDCO_16MHZ;                		// Set uC to run at approximately 16 Mhz
	BCSCTL1 = CALBC1_16MHZ; 
	
	
	// Timer A1 config - PWM
	// set up timer A1 to have period of ~8KHz, 255 step resolution (2MHz update)
	TA1CCR0 = 255;				// ~8KHz period, we use /8 clock divider
	TA1CCR1 = TA1CCR2 = 0;		// set both off
	TA1CTL = TASSEL_2 + MC_1 + ID_3;	// source SMCLK, up mode, /8 clock divider
	TA1CCTL1 = OUTMOD_7;		// reset/set - starts high
	TA1CCTL2 = OUTMOD_7;		// reset/set - starts high
	
	// set up periodic tick, 100 times/second
	// Timer A0 Config - periodic interrupts
	TA0CCTL0 = CCIE;                           // Enable interrupt
	TA0CCR0 = 20000;                           // period = 10ms (20000 * 8 cycles)   
	TA0CTL = TASSEL_2 + MC_1 + ID_3;           // source SMCLK, up mode, /8 divider
	// set up status "I'm alive!" LED
	P1DIR |= 0x1;								// Default LED output - P1.0
	
	
	
	setup_ADC();	

// enable P2.1 and P2.4 as PWM outputs
	SET_BIT8(P2DIR, 1);		// output
	SET_BIT8(P2SEL, 1);		// set P2.1 as timer 1.1 out
	SET_BIT8(P2DIR, 4);		// output
	SET_BIT8(P2SEL, 4);		// set P2.4 as timer 1.2 out

	TA1CCR1 = TA1CCR2 = PWM_INITIAL;

	_BIS_SR(GIE); 						   // Enable global interrupt

	
	while(1) {  
	}  // while
} // main()

// Timer A0 interrupt service routine
#pragma vector=TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
	timecnt++; // Keep track of time for main while loop. 

	if (timecnt%50 == 0) {  // 1/2 second
		P1OUT ^= 0x1;		// Blink LED
	}

	// start ADC conversion.  Actual logic happens in the ADC interrupt when conversion
	// is done.
	ADC10SA = (unsigned int)data;	// reset DTC base address
	ADC10CTL0 |= ADC10SC;	// start conversion - control will happen in ADC ISR	

}  // timer A ISR


// ADC 10 ISR - Called when a sequence of conversions (A7-A0) have completed
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void) {
	
	// set PWM on P2.1 to be result from A4, PWM on P2.4 to be result from A5
	// because DTC puts data in "backwards", A5 is in data[0], A4 is in data[1]
	TA1CCR1 = data[1] >> 2;
	TA1CCR2 = data[0] >> 2;
}




